import {
  IsString,
  IsOptional,
  IsEnum,
  IsBoolean,
  IsArray,
  IsUUID,
  IsInt,
  IsUrl,
  IsDateString,
  IsMimeType,
  MinLength,
  MaxLength,
  Min,
  Max,
  Matches,
  ValidateNested,
  ArrayMinSize,
  ArrayMaxSize,
  IsNumber,
  IsPositive
} from 'class-validator'
import { Type, Transform, Expose, Exclude } from 'class-transformer'
import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger'
import { BaseDto, PaginationDto } from './base.dto'

/**
 * 文件类型枚举
 */
export enum FileType {
  IMAGE = 'image',
  VIDEO = 'video',
  AUDIO = 'audio',
  DOCUMENT = 'document',
  ARCHIVE = 'archive',
  OTHER = 'other'
}

/**
 * 文件状态枚举
 */
export enum FileStatus {
  UPLOADING = 'uploading',
  PROCESSING = 'processing',
  COMPLETED = 'completed',
  FAILED = 'failed',
  DELETED = 'deleted'
}

/**
 * 文件访问权限枚举
 */
export enum FileAccess {
  PUBLIC = 'public',
  PRIVATE = 'private',
  PROTECTED = 'protected',
  INTERNAL = 'internal'
}

/**
 * 图片处理操作枚举
 */
export enum ImageOperation {
  RESIZE = 'resize',
  CROP = 'crop',
  ROTATE = 'rotate',
  FLIP = 'flip',
  WATERMARK = 'watermark',
  COMPRESS = 'compress',
  FORMAT = 'format'
}

/**
 * 文件上传DTO
 */
export class FileUploadDto {
  @ApiPropertyOptional({ description: '文件名称' })
  @IsOptional()
  @IsString()
  @MaxLength(255)
  filename?: string

  @ApiPropertyOptional({ description: '文件描述' })
  @IsOptional()
  @IsString()
  @MaxLength(500)
  description?: string

  @ApiPropertyOptional({ description: '文件标签' })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  @ArrayMaxSize(10)
  tags?: string[]

  @ApiPropertyOptional({ description: '文件分类' })
  @IsOptional()
  @IsString()
  @MaxLength(50)
  category?: string

  @ApiPropertyOptional({ description: '访问权限', enum: FileAccess })
  @IsOptional()
  @IsEnum(FileAccess)
  access?: FileAccess = FileAccess.PUBLIC

  @ApiPropertyOptional({ description: '是否压缩图片' })
  @IsOptional()
  @IsBoolean()
  compress?: boolean = true

  @ApiPropertyOptional({ description: '图片质量（1-100）' })
  @IsOptional()
  @IsInt()
  @Min(1)
  @Max(100)
  quality?: number = 80

  @ApiPropertyOptional({ description: '最大宽度' })
  @IsOptional()
  @IsInt()
  @Min(1)
  @Max(10000)
  maxWidth?: number

  @ApiPropertyOptional({ description: '最大高度' })
  @IsOptional()
  @IsInt()
  @Min(1)
  @Max(10000)
  maxHeight?: number

  @ApiPropertyOptional({ description: '是否生成缩略图' })
  @IsOptional()
  @IsBoolean()
  generateThumbnail?: boolean = true

  @ApiPropertyOptional({ description: '缩略图尺寸' })
  @IsOptional()
  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => ThumbnailSizeDto)
  thumbnailSizes?: ThumbnailSizeDto[]

  @ApiPropertyOptional({ description: '水印文本' })
  @IsOptional()
  @IsString()
  @MaxLength(100)
  watermarkText?: string

  @ApiPropertyOptional({ description: '水印位置' })
  @IsOptional()
  @IsEnum(['top-left', 'top-right', 'bottom-left', 'bottom-right', 'center'])
  watermarkPosition?: string

  @ApiPropertyOptional({ description: '水印透明度（0-1）' })
  @IsOptional()
  @IsNumber()
  @Min(0)
  @Max(1)
  watermarkOpacity?: number = 0.5

  @ApiPropertyOptional({ description: '存储路径' })
  @IsOptional()
  @IsString()
  @MaxLength(200)
  storagePath?: string

  @ApiPropertyOptional({ description: '过期时间' })
  @IsOptional()
  @IsDateString()
  expiresAt?: string

  @ApiPropertyOptional({ description: '元数据' })
  @IsOptional()
  metadata?: Record<string, any>
}

/**
 * 缩略图尺寸DTO
 */
export class ThumbnailSizeDto {
  @ApiProperty({ description: '宽度' })
  @IsInt()
  @Min(1)
  @Max(2000)
  width: number

  @ApiProperty({ description: '高度' })
  @IsInt()
  @Min(1)
  @Max(2000)
  height: number

  @ApiPropertyOptional({ description: '尺寸名称' })
  @IsOptional()
  @IsString()
  @MaxLength(20)
  name?: string

  @ApiPropertyOptional({ description: '是否保持比例' })
  @IsOptional()
  @IsBoolean()
  keepAspectRatio?: boolean = true

  @ApiPropertyOptional({ description: '裁剪模式' })
  @IsOptional()
  @IsEnum(['fit', 'fill', 'crop'])
  cropMode?: string = 'fit'
}

/**
 * 文件信息DTO
 */
export class FileDto extends BaseDto {
  @ApiProperty({ description: '文件名称' })
  @Expose()
  filename: string

  @ApiProperty({ description: '原始文件名' })
  @Expose()
  originalName: string

  @ApiProperty({ description: '文件类型', enum: FileType })
  @Expose()
  type: FileType

  @ApiProperty({ description: 'MIME类型' })
  @Expose()
  mimeType: string

  @ApiProperty({ description: '文件大小（字节）' })
  @Expose()
  size: number

  @ApiProperty({ description: '文件路径' })
  @Expose()
  path: string

  @ApiProperty({ description: '文件URL' })
  @Expose()
  url: string

  @ApiPropertyOptional({ description: '缩略图URL' })
  @Expose()
  thumbnailUrl?: string

  @ApiPropertyOptional({ description: '预览URL' })
  @Expose()
  previewUrl?: string

  @ApiProperty({ description: '文件状态', enum: FileStatus })
  @Expose()
  status: FileStatus

  @ApiProperty({ description: '访问权限', enum: FileAccess })
  @Expose()
  access: FileAccess

  @ApiPropertyOptional({ description: '文件描述' })
  @Expose()
  description?: string

  @ApiPropertyOptional({ description: '文件标签' })
  @Expose()
  tags?: string[]

  @ApiPropertyOptional({ description: '文件分类' })
  @Expose()
  category?: string

  @ApiProperty({ description: '上传者ID' })
  @Expose()
  uploaderId: string

  @ApiPropertyOptional({ description: '上传者信息' })
  @Expose()
  uploader?: {
    id: string
    username: string
    nickname?: string
    avatar?: string
  }

  @ApiPropertyOptional({ description: '文件哈希值' })
  @Expose()
  hash?: string

  @ApiPropertyOptional({ description: '文件元数据' })
  @Expose()
  metadata?: Record<string, any>

  @ApiPropertyOptional({ description: '图片信息' })
  @Expose()
  imageInfo?: {
    width: number
    height: number
    format: string
    colorSpace?: string
    hasAlpha?: boolean
    orientation?: number
  }

  @ApiPropertyOptional({ description: '视频信息' })
  @Expose()
  videoInfo?: {
    duration: number
    width: number
    height: number
    format: string
    codec: string
    bitrate?: number
    frameRate?: number
  }

  @ApiPropertyOptional({ description: '音频信息' })
  @Expose()
  audioInfo?: {
    duration: number
    format: string
    codec: string
    bitrate?: number
    sampleRate?: number
    channels?: number
  }

  @ApiPropertyOptional({ description: '下载次数' })
  @Expose()
  downloadCount?: number = 0

  @ApiPropertyOptional({ description: '查看次数' })
  @Expose()
  viewCount?: number = 0

  @ApiPropertyOptional({ description: '最后访问时间' })
  @Expose()
  lastAccessedAt?: Date

  @ApiPropertyOptional({ description: '过期时间' })
  @Expose()
  expiresAt?: Date

  @ApiPropertyOptional({ description: '存储提供商' })
  @Expose()
  storageProvider?: string

  @ApiPropertyOptional({ description: '存储区域' })
  @Expose()
  storageRegion?: string

  @ApiPropertyOptional({ description: '存储桶' })
  @Expose()
  storageBucket?: string

  @ApiPropertyOptional({ description: '是否已删除' })
  @Expose()
  isDeleted?: boolean = false

  @ApiPropertyOptional({ description: '删除时间' })
  @Expose()
  deletedAt?: Date
}

/**
 * 更新文件DTO
 */
export class UpdateFileDto {
  @ApiPropertyOptional({ description: '文件名称' })
  @IsOptional()
  @IsString()
  @MaxLength(255)
  filename?: string

  @ApiPropertyOptional({ description: '文件描述' })
  @IsOptional()
  @IsString()
  @MaxLength(500)
  description?: string

  @ApiPropertyOptional({ description: '文件标签' })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  @ArrayMaxSize(10)
  tags?: string[]

  @ApiPropertyOptional({ description: '文件分类' })
  @IsOptional()
  @IsString()
  @MaxLength(50)
  category?: string

  @ApiPropertyOptional({ description: '访问权限', enum: FileAccess })
  @IsOptional()
  @IsEnum(FileAccess)
  access?: FileAccess

  @ApiPropertyOptional({ description: '过期时间' })
  @IsOptional()
  @IsDateString()
  expiresAt?: string

  @ApiPropertyOptional({ description: '元数据' })
  @IsOptional()
  metadata?: Record<string, any>
}

/**
 * 查询文件DTO
 */
export class QueryFileDto extends PaginationDto {
  @ApiPropertyOptional({ description: '文件类型', enum: FileType })
  @IsOptional()
  @IsEnum(FileType)
  type?: FileType

  @ApiPropertyOptional({ description: '文件状态', enum: FileStatus })
  @IsOptional()
  @IsEnum(FileStatus)
  status?: FileStatus

  @ApiPropertyOptional({ description: '访问权限', enum: FileAccess })
  @IsOptional()
  @IsEnum(FileAccess)
  access?: FileAccess

  @ApiPropertyOptional({ description: '文件分类' })
  @IsOptional()
  @IsString()
  @MaxLength(50)
  category?: string

  @ApiPropertyOptional({ description: '上传者ID' })
  @IsOptional()
  @IsUUID()
  uploaderId?: string

  @ApiPropertyOptional({ description: '文件标签' })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  tags?: string[]

  @ApiPropertyOptional({ description: '最小文件大小（字节）' })
  @IsOptional()
  @IsInt()
  @Min(0)
  minSize?: number

  @ApiPropertyOptional({ description: '最大文件大小（字节）' })
  @IsOptional()
  @IsInt()
  @Min(0)
  maxSize?: number

  @ApiPropertyOptional({ description: '开始时间' })
  @IsOptional()
  @IsDateString()
  startDate?: string

  @ApiPropertyOptional({ description: '结束时间' })
  @IsOptional()
  @IsDateString()
  endDate?: string

  @ApiPropertyOptional({ description: '搜索关键词' })
  @IsOptional()
  @IsString()
  @MaxLength(100)
  search?: string = ''

  @ApiPropertyOptional({ description: 'MIME类型' })
  @IsOptional()
  @IsArray()
  @IsMimeType({ each: true })
  mimeTypes?: string[]

  @ApiPropertyOptional({ description: '是否包含已删除文件' })
  @IsOptional()
  @Transform(({ value }) => value === 'true')
  @IsBoolean()
  includeDeleted?: boolean = false

  @ApiPropertyOptional({ description: '是否只显示图片' })
  @IsOptional()
  @Transform(({ value }) => value === 'true')
  @IsBoolean()
  imagesOnly?: boolean

  @ApiPropertyOptional({ description: '是否只显示视频' })
  @IsOptional()
  @Transform(({ value }) => value === 'true')
  @IsBoolean()
  videosOnly?: boolean

  @ApiPropertyOptional({ description: '是否只显示文档' })
  @IsOptional()
  @Transform(({ value }) => value === 'true')
  @IsBoolean()
  documentsOnly?: boolean
}

/**
 * 批量文件操作DTO
 */
export class BulkFileOperationDto {
  @ApiProperty({ description: '文件ID列表' })
  @IsArray()
  @IsUUID(4, { each: true })
  @ArrayMinSize(1)
  @ArrayMaxSize(100)
  fileIds: string[]

  @ApiProperty({ description: '操作类型' })
  @IsEnum(['delete', 'restore', 'move', 'copy', 'changeAccess', 'addTags', 'removeTags'])
  operation: 'delete' | 'restore' | 'move' | 'copy' | 'changeAccess' | 'addTags' | 'removeTags'

  @ApiPropertyOptional({ description: '目标路径（移动/复制操作）' })
  @IsOptional()
  @IsString()
  @MaxLength(200)
  targetPath?: string

  @ApiPropertyOptional({ description: '新的访问权限（权限变更操作）' })
  @IsOptional()
  @IsEnum(FileAccess)
  newAccess?: FileAccess

  @ApiPropertyOptional({ description: '标签列表（标签操作）' })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  @ArrayMaxSize(10)
  tags?: string[]

  @ApiPropertyOptional({ description: '操作原因' })
  @IsOptional()
  @IsString()
  @MaxLength(200)
  reason?: string
}

/**
 * 图片处理DTO
 */
export class ImageProcessDto {
  @ApiProperty({ description: '处理操作', enum: ImageOperation })
  @IsEnum(ImageOperation)
  operation: ImageOperation

  @ApiPropertyOptional({ description: '宽度' })
  @IsOptional()
  @IsInt()
  @Min(1)
  @Max(10000)
  width?: number

  @ApiPropertyOptional({ description: '高度' })
  @IsOptional()
  @IsInt()
  @Min(1)
  @Max(10000)
  height?: number

  @ApiPropertyOptional({ description: '质量（1-100）' })
  @IsOptional()
  @IsInt()
  @Min(1)
  @Max(100)
  quality?: number = 80

  @ApiPropertyOptional({ description: '输出格式' })
  @IsOptional()
  @IsEnum(['jpeg', 'png', 'webp', 'avif', 'tiff'])
  format?: string

  @ApiPropertyOptional({ description: '旋转角度' })
  @IsOptional()
  @IsInt()
  @Min(-360)
  @Max(360)
  rotation?: number

  @ApiPropertyOptional({ description: '翻转方向' })
  @IsOptional()
  @IsEnum(['horizontal', 'vertical'])
  flip?: string

  @ApiPropertyOptional({ description: '裁剪区域' })
  @IsOptional()
  @ValidateNested()
  @Type(() => CropAreaDto)
  cropArea?: CropAreaDto

  @ApiPropertyOptional({ description: '水印文本' })
  @IsOptional()
  @IsString()
  @MaxLength(100)
  watermarkText?: string

  @ApiPropertyOptional({ description: '水印图片URL' })
  @IsOptional()
  @IsUrl()
  watermarkImageUrl?: string

  @ApiPropertyOptional({ description: '水印位置' })
  @IsOptional()
  @IsEnum(['top-left', 'top-right', 'bottom-left', 'bottom-right', 'center'])
  watermarkPosition?: string = 'bottom-right'

  @ApiPropertyOptional({ description: '水印透明度（0-1）' })
  @IsOptional()
  @IsNumber()
  @Min(0)
  @Max(1)
  watermarkOpacity?: number = 0.5

  @ApiPropertyOptional({ description: '是否保持比例' })
  @IsOptional()
  @IsBoolean()
  keepAspectRatio?: boolean = true

  @ApiPropertyOptional({ description: '背景颜色（十六进制）' })
  @IsOptional()
  @Matches(/^#[0-9A-Fa-f]{6}$/)
  backgroundColor?: string = '#ffffff'
}

/**
 * 裁剪区域DTO
 */
export class CropAreaDto {
  @ApiProperty({ description: 'X坐标' })
  @IsInt()
  @Min(0)
  x: number

  @ApiProperty({ description: 'Y坐标' })
  @IsInt()
  @Min(0)
  y: number

  @ApiProperty({ description: '宽度' })
  @IsInt()
  @Min(1)
  width: number

  @ApiProperty({ description: '高度' })
  @IsInt()
  @Min(1)
  height: number
}

/**
 * 文件统计DTO
 */
export class FileStatsDto {
  @ApiProperty({ description: '总文件数' })
  @Expose()
  totalFiles: number

  @ApiProperty({ description: '总文件大小（字节）' })
  @Expose()
  totalSize: number

  @ApiProperty({ description: '按类型统计' })
  @Expose()
  byType: Record<
    FileType,
    {
      count: number
      size: number
      percentage: number
    }
  >

  @ApiProperty({ description: '按状态统计' })
  @Expose()
  byStatus: Record<FileStatus, number>

  @ApiProperty({ description: '按访问权限统计' })
  @Expose()
  byAccess: Record<FileAccess, number>

  @ApiProperty({ description: '按月份统计' })
  @Expose()
  byMonth: Array<{
    month: string
    count: number
    size: number
  }>

  @ApiProperty({ description: '热门文件类型' })
  @Expose()
  popularTypes: Array<{
    type: string
    count: number
    percentage: number
  }>

  @ApiProperty({ description: '最大文件' })
  @Expose()
  largestFiles: Array<{
    id: string
    filename: string
    size: number
    type: FileType
  }>

  @ApiProperty({ description: '最近上传' })
  @Expose()
  recentUploads: Array<{
    id: string
    filename: string
    uploadedAt: Date
    uploader: string
  }>

  @ApiProperty({ description: '存储使用情况' })
  @Expose()
  storageUsage: {
    used: number
    limit: number
    percentage: number
    remaining: number
  }
}

/**
 * 文件分享DTO
 */
export class FileShareDto {
  @ApiProperty({ description: '文件ID' })
  @IsUUID()
  fileId: string

  @ApiPropertyOptional({ description: '分享类型' })
  @IsOptional()
  @IsEnum(['link', 'email', 'qrcode'])
  shareType?: string = 'link'

  @ApiPropertyOptional({ description: '过期时间' })
  @IsOptional()
  @IsDateString()
  expiresAt?: string

  @ApiPropertyOptional({ description: '访问密码' })
  @IsOptional()
  @IsString()
  @MinLength(4)
  @MaxLength(20)
  password?: string

  @ApiPropertyOptional({ description: '最大下载次数' })
  @IsOptional()
  @IsInt()
  @Min(1)
  @Max(1000)
  maxDownloads?: number

  @ApiPropertyOptional({ description: '允许预览' })
  @IsOptional()
  @IsBoolean()
  allowPreview?: boolean = true

  @ApiPropertyOptional({ description: '分享给的邮箱列表' })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  @ArrayMaxSize(10)
  emails?: string[]

  @ApiPropertyOptional({ description: '分享消息' })
  @IsOptional()
  @IsString()
  @MaxLength(500)
  message?: string
}

/**
 * 文件分享响应DTO
 */
export class FileShareResponseDto {
  @ApiProperty({ description: '分享ID' })
  @Expose()
  shareId: string

  @ApiProperty({ description: '分享链接' })
  @Expose()
  shareUrl: string

  @ApiPropertyOptional({ description: '二维码URL' })
  @Expose()
  qrCodeUrl?: string

  @ApiProperty({ description: '过期时间' })
  @Expose()
  expiresAt: Date

  @ApiProperty({ description: '创建时间' })
  @Expose()
  createdAt: Date

  @ApiPropertyOptional({ description: '访问次数' })
  @Expose()
  accessCount?: number = 0

  @ApiPropertyOptional({ description: '下载次数' })
  @Expose()
  downloadCount?: number = 0

  @ApiPropertyOptional({ description: '最大下载次数' })
  @Expose()
  maxDownloads?: number

  @ApiProperty({ description: '是否需要密码' })
  @Expose()
  requiresPassword: boolean
}

/**
 * 文件夹DTO
 */
export class FolderDto extends BaseDto {
  @ApiProperty({ description: '文件夹名称' })
  @Expose()
  name: string

  @ApiProperty({ description: '文件夹路径' })
  @Expose()
  path: string

  @ApiPropertyOptional({ description: '父文件夹ID' })
  @Expose()
  parentId?: string

  @ApiPropertyOptional({ description: '文件夹描述' })
  @Expose()
  description?: string

  @ApiProperty({ description: '访问权限', enum: FileAccess })
  @Expose()
  access: FileAccess

  @ApiProperty({ description: '创建者ID' })
  @Expose()
  creatorId: string

  @ApiPropertyOptional({ description: '创建者信息' })
  @Expose()
  creator?: {
    id: string
    username: string
    nickname?: string
  }

  @ApiProperty({ description: '文件数量' })
  @Expose()
  fileCount: number = 0

  @ApiProperty({ description: '子文件夹数量' })
  @Expose()
  folderCount: number = 0

  @ApiProperty({ description: '总大小（字节）' })
  @Expose()
  totalSize: number = 0

  @ApiPropertyOptional({ description: '是否为系统文件夹' })
  @Expose()
  isSystem?: boolean = false

  @ApiPropertyOptional({ description: '排序权重' })
  @Expose()
  sort?: number = 0
}

/**
 * 创建文件夹DTO
 */
export class CreateFolderDto {
  @ApiProperty({ description: '文件夹名称' })
  @IsString()
  @MinLength(1)
  @MaxLength(100)
  @Matches(/^[^<>:"/\\|?*]+$/, { message: '文件夹名称包含非法字符' })
  name: string

  @ApiPropertyOptional({ description: '父文件夹ID' })
  @IsOptional()
  @IsUUID()
  parentId?: string

  @ApiPropertyOptional({ description: '文件夹描述' })
  @IsOptional()
  @IsString()
  @MaxLength(500)
  description?: string

  @ApiPropertyOptional({ description: '访问权限', enum: FileAccess })
  @IsOptional()
  @IsEnum(FileAccess)
  access?: FileAccess = FileAccess.PUBLIC

  @ApiPropertyOptional({ description: '排序权重' })
  @IsOptional()
  @IsInt()
  @Min(0)
  sort?: number = 0
}

/**
 * 更新文件夹DTO
 */
export class UpdateFolderDto extends PartialType(CreateFolderDto) {}

/**
 * 文件上传响应DTO
 */
export class FileUploadResponseDto {
  @ApiProperty({ description: '文件ID' })
  @Expose()
  id: string

  @ApiProperty({ description: '文件名称' })
  @Expose()
  filename: string

  @ApiProperty({ description: '原始文件名' })
  @Expose()
  originalName: string

  @ApiProperty({ description: '文件URL' })
  @Expose()
  url: string

  @ApiPropertyOptional({ description: '缩略图URL' })
  @Expose()
  thumbnailUrl?: string

  @ApiProperty({ description: '文件大小（字节）' })
  @Expose()
  size: number

  @ApiProperty({ description: 'MIME类型' })
  @Expose()
  mimeType: string

  @ApiProperty({ description: '文件类型', enum: FileType })
  @Expose()
  type: FileType

  @ApiProperty({ description: '文件哈希值' })
  @Expose()
  hash: string

  @ApiProperty({ description: '上传时间' })
  @Expose()
  uploadedAt: Date

  @ApiPropertyOptional({ description: '处理状态' })
  @Expose()
  processingStatus?: 'pending' | 'processing' | 'completed' | 'failed'

  @ApiPropertyOptional({ description: '错误信息' })
  @Expose()
  error?: string

  @ApiPropertyOptional({ description: '元数据' })
  @Expose()
  metadata?: Record<string, any>
}

/**
 * 文件下载DTO
 */
export class FileDownloadDto {
  @ApiPropertyOptional({ description: '是否强制下载' })
  @IsOptional()
  @Transform(({ value }) => value === 'true')
  @IsBoolean()
  forceDownload?: boolean = false

  @ApiPropertyOptional({ description: '下载文件名' })
  @IsOptional()
  @IsString()
  @MaxLength(255)
  filename?: string

  @ApiPropertyOptional({ description: '访问令牌' })
  @IsOptional()
  @IsString()
  token?: string
}
